package com.zj.weather.bgviews.light.child;

import android.content.Context;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.os.Build;

import com.zj.weather.bgviews.light.LightInfo;
import com.zj.weather.bgviews.light.TentacleInfo;
import com.zj.weather.utils.DisplayUtils;
import com.zj.weather.utils.PathAliasChangeUtils;

import java.util.ArrayList;
import java.util.List;

import static android.os.Build.VERSION_CODES.KITKAT;
import static com.zj.weather.bgviews.light.LightUtils.getEffectPaint;
import static com.zj.weather.utils.RandomUtils.getRandom;

/**
 * Created by zhaojie on 2018/8/14.
 */

public class LargeLightInfo extends LightInfo {

    private final static float maxStepInterval = 15, minStepInterval = 5;
    private final static float tentacleSpeed = 0.008f;//
    private final static float speed = 0.133f;//
    private final static float maxTentacleSpeedOffset = tentacleSpeed * 0.55f, minTentacleSpeedOffset = tentacleSpeed * -0.25f;
    private final static float maxTentacleWidth = 0.5f, minTentacleWidth = 0.1f;
    //电触基础宽度补偿
    private final static float tentacleWidthEqualize = 0.17f;
    private final static float maxXOffset = 5, minXOffset = -5;//
    private final static float maxXDur = 18, minXDur = -18;//
    private final static float maxDeviation = 5;
    private final static int maxTentacle = 3;
    private final static int maxTentacleChild = 15;
    //视网膜残留时间。
    private final static float maxLightHeight = 1.3f;
    private final static float tentacleAlpha = 0.55f;
    private final float maxWidth = 9;
    private float curY;
    private float tentacleY;
    private float curX;
    private Path path;
    private List<TentacleInfo> tentacles;
    private float xOffset;
    private int tentacleId;
    //自增量，用于为电触设置唯一ID；
    private int curTentacleId = 0xf1;
    private BlurMaskFilter blurMaskFilter;

    public LargeLightInfo(float width, float height, float cloudHeight, float maxAlpha, float speed, int branch, int maxShiningCount) {
        super(width, height, cloudHeight, maxAlpha, speed, branch, maxShiningCount);
    }

    @Override
    public void initData(Context context) {
        fraction = 0.0f;
        curX = getRandom(0.2f, 0.8f) * width;
        xOffset = getRandom(DisplayUtils.dip2px(context, minXOffset), DisplayUtils.dip2px(context, maxXOffset));
        path = new Path();
        blurMaskFilter = new BlurMaskFilter(DisplayUtils.dip2px(context, maxWidth * 2f), BlurMaskFilter.Blur.SOLID);
        path.moveTo(curX, DisplayUtils.dip2px(context, curY));
        if (tentacles == null)
            tentacles = new ArrayList<>();
        else tentacles.clear();
    }

    @Override
    public boolean draw(Context context, Canvas canvas, float changeAlpha) {
        boolean isFinishLight = false;
        super.draw(context, canvas, changeAlpha);
        if (!isLightTentacleEnd) {
            tentacleY += (tentacleSpeed + getRandom(minTentacleSpeedOffset, maxTentacleSpeedOffset)) * height;
            curX += xOffset + getRandom(minXDur, maxXDur);
            path.lineTo(curX, tentacleY);
            if (tentacleY > height) {
                tentacleY = height;
            }
            PathAliasChangeUtils.PathClipInfo clipInfo = PathAliasChangeUtils.getAliasPathClip(0.9f, 1.0f, 0.1f, maxTentacleWidth, minTentacleWidth, false, path);
            Paint paint = getPaint(context, changeAlpha * tentacleAlpha, clipInfo.maxWidth, false);
            canvas.drawPath(clipInfo.surplusPath, paint);
            for (PathAliasChangeUtils.PathChangeInfo changeInfo : clipInfo.pathChanges) {
                paint.setStrokeWidth(changeInfo.width);
                canvas.drawPath(changeInfo.path, paint);
            }
            if (tentacleY < height) {
                if (canAddTentacle(5f, tentacles.size(), maxTentacle, tentacleY)) {
                    float childWidth = getRandom(0.3f, 0.7f);
                    tentacles.add(new TentacleInfo(path, 1, curX, tentacleY, height, (childWidth + tentacleWidthEqualize) * maxTentacleWidth, getRandom(minXOffset, maxXOffset), tentacleAlpha, tentacleSpeed + getRandom(minTentacleSpeedOffset, maxTentacleSpeedOffset), 0, curTentacleId += 1));
                    xOffset = getRandom(DisplayUtils.dip2px(context, minXOffset), DisplayUtils.dip2px(context, maxXOffset));
                }
                buildTentacle(context, canvas);
            } else {
                whenFirstTentacleFinished(path, 0);
            }
        } else {
            List<TentacleInfo> adjoinTentacles = new ArrayList<>();
            for (TentacleInfo info : tentacles) {
                //某一个子电触到达底部
                if (tentacleId != 0 && info.id == tentacleId) {
                    adjoinTentacles = addAdjoinList(info.id, adjoinTentacles);
                    break;
                }
                //最初的电触到达底部
                if (tentacleId == 0) {
                    if (info.id != tentacleId && info.parent == tentacleId) {
                        adjoinTentacles.add(info);
                    }
                }
            }
            isFinishLight = drawLight(context, canvas, changeAlpha);
            for (TentacleInfo adJoinInfo : adjoinTentacles) {
                if (adJoinInfo.alpha > 0 && curY >= adJoinInfo.startY) {
                    float endTentacleWidth = DisplayUtils.dip2px(context, (maxLightHeight - curY / height) * maxWidth * (adJoinInfo.width / maxTentacleWidth));
                    adJoinInfo.draw(getPaint(context, changeAlpha * 1.0f, endTentacleWidth, false), endTentacleWidth, minTentacleWidth, false, 0.0f, getRandom(0.3f, 0.8f), 0.1f, canvas);
                }
            }
        }
        if (isFinishLight) {
            shiningCount = 0;
            path.rewind();
            fraction = 0.0f;
            curX = 0;
            path = null;
            tentacles.clear();
        }
        return isFinishLight;
    }

    //递归计算碰撞id，找出所有与当前path交汇的电触
    private List<TentacleInfo> addAdjoinList(int curId, List<TentacleInfo> adjoinTentacles) {
        int nextId = 0;
        for (TentacleInfo tentacleInfo : tentacles) {
            boolean isSameInfo = tentacleInfo.id == curId;
            if (isSameInfo || tentacleInfo.parent == curId) {
                adjoinTentacles.add(tentacleInfo);
                if (isSameInfo) nextId = tentacleInfo.parent;
            }
        }
        return (nextId != 0) ? addAdjoinList(nextId, adjoinTentacles) : adjoinTentacles;
    }

    private boolean isLightTentacleEnd = false;

    private boolean drawLight(Context c, Canvas canvas, float curAlpha) {
        curY += speed * height;
        PathMeasure pathMeasure = new PathMeasure(path, false);
        Path lightPath = new Path();
        if (Build.VERSION.SDK_INT <= KITKAT) lightPath.lineTo(0, 0);
        fraction = Math.min(1.0f, curY / height);
        pathMeasure.getSegment(0.0f, fraction * pathMeasure.getLength(), lightPath, true);
        if (shiningCount < maxShiningCount) {
            if (isShining) {
                canvas.drawColor(0x90ffffff);
            } else {
                canvas.drawColor(0);
            }
            isShining = !isShining;
            shiningCount++;
        }
        float lightWidth = DisplayUtils.dip2px(c, (maxLightHeight - curY / height) * maxWidth);
        canvas.drawPath(lightPath, getPaint(c, curAlpha, lightWidth, true));
        return curY > height * maxLightHeight;
    }

    private void buildTentacle(Context c, Canvas canvas) {
        if (!isLightTentacleEnd) {
            if (tentacles != null && tentacles.size() > 0) {
                List<TentacleInfo> addList = new ArrayList();
                List<TentacleInfo> removeList = new ArrayList();
                for (TentacleInfo info : tentacles) {
                    info.upDateParams(tentacles);
                    if (info.alpha <= 0f) {
                        removeList.add(info);
                    } else {
                        info.setNewPosition(DisplayUtils.dip2px(c, getRandom(minXOffset, maxXOffset)), getRandom(info.speed * 0.1f, info.speed * 1.2f) * height);
                        info.draw(getPaint(c, info.alpha, info.width, false), info.width, minTentacleWidth, true, 0.7f, 1.0f, 0.1f, canvas);
                        if (info.curY >= height) {
                            whenFirstTentacleFinished(info.allPath, info.id);
                            break;
                        } else if (canAddTentacle(9.6f, addList.size() + tentacles.size(), maxTentacleChild, info.curY)) {
                            float branchWidth = getRandom(0.3f, 0.7f);
                            float childWidth = (1.0f - branchWidth + tentacleWidthEqualize) * info.width;
                            info.width = (branchWidth + tentacleWidthEqualize) * info.width;
                            addList.add(new TentacleInfo(info.allPath, info.layer + 1, info.curX, info.curY, height, childWidth, getRandom(minXOffset, maxXOffset), info.alpha, info.speed + getRandom(minTentacleSpeedOffset, maxTentacleSpeedOffset), info.id, curTentacleId += 1));
                            info.resetX(getRandom(minXOffset, maxXOffset));
                        }
                    }
                }
                tentacles.addAll(addList);
                tentacles.removeAll(removeList);
                addList.clear();
                removeList.clear();
            }
        }
    }

    private float lastTentacleY;

    private boolean canAddTentacle(float maxOdds, int curSize, int maxSize, float curY) {
        boolean isNearbyLast = Math.abs(lastTentacleY - curY) >= 0.1f * height;
        if (isNearbyLast) lastTentacleY = curY;
        return getRandom(0f, 10f) > maxOdds && curSize < maxSize && isNearbyLast;
    }

    private void whenFirstTentacleFinished(Path finishPath, int tentacleId) {
        this.path.set(finishPath);
        this.tentacleId = tentacleId;
        this.isLightTentacleEnd = true;
    }

    private Paint getPaint(Context context, float curAlpha, float width, boolean isAddEffect) {
        return getEffectPaint(context, (int) (curAlpha * 255f), width, minStepInterval, maxStepInterval, maxDeviation, blurMaskFilter, isAddEffect);
    }

}
